using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Matrix.ServiceCommunication.Options;
using Matrix.ServiceCommunication.Services;
using Matrix.ServiceCommunication.Monitoring;

namespace Matrix.ServiceCommunication
{
    /// <summary>
    /// Matrix服务通信客户端
    /// 轻量级SDK，提供服务间通信的核心能力
    /// </summary>
    public class MatrixServiceClient : IMatrixServiceClient
    {
        private readonly IServiceClientFactory _clientFactory;
        private readonly IOptionsMonitor<ServiceCommunicationOptions> _options;
        private readonly ILogger<MatrixServiceClient> _logger;
        private readonly IServiceCommunicationMetrics _metrics;

        public MatrixServiceClient(
            IServiceClientFactory clientFactory,
            IOptionsMonitor<ServiceCommunicationOptions> options,
            ILogger<MatrixServiceClient> logger,
            IServiceCommunicationMetrics metrics)
        {
            _clientFactory = clientFactory ?? throw new ArgumentNullException(nameof(clientFactory));
            _options = options ?? throw new ArgumentNullException(nameof(options));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
            _metrics = metrics ?? throw new ArgumentNullException(nameof(metrics));
        }

        /// <summary>
        /// 创建HTTP客户端
        /// </summary>
        public HttpClient CreateClient(string serviceName)
        {
            _logger.LogDebug("创建服务客户端: {ServiceName}", serviceName);
            _metrics.IncrementClientCreated(serviceName);

            return _clientFactory.CreateClient(serviceName);
        }

        /// <summary>
        /// 创建带用户上下文的HTTP客户端
        /// </summary>
        public async Task<HttpClient> CreateClientAsync(string serviceName, UserContext? userContext = null, CancellationToken cancellationToken = default)
        {
            _logger.LogDebug("创建异步服务客户端: {ServiceName}, 用户上下文: {HasUserContext}",
                serviceName, userContext != null);

            _metrics.IncrementClientCreated(serviceName);

            var client = await _clientFactory.CreateClientAsync(serviceName, userContext, cancellationToken);

            // 添加监控拦截器
            client = AddMonitoringInterceptor(client, serviceName);

            return client;
        }

        /// <summary>
        /// 获取服务地址
        /// </summary>
        public async Task<Uri> GetServiceAddressAsync(string serviceName, CancellationToken cancellationToken = default)
        {
            _logger.LogDebug("获取服务地址: {ServiceName}", serviceName);

            try
            {
                var address = await _clientFactory.GetServiceAddressAsync(serviceName, cancellationToken);
                _metrics.RecordServiceDiscovery(serviceName, true);

                _logger.LogDebug("获取服务地址成功: {ServiceName} -> {Address}", serviceName, address);
                return address;
            }
            catch (Exception ex)
            {
                _metrics.RecordServiceDiscovery(serviceName, false);
                _logger.LogError(ex, "获取服务地址失败: {ServiceName}", serviceName);
                throw;
            }
        }

        /// <summary>
        /// 执行GET请求
        /// </summary>
        public async Task<TResponse?> GetAsync<TResponse>(
            string serviceName,
            string path,
            UserContext? userContext = null,
            CancellationToken cancellationToken = default)
        {
            using var client = await CreateClientAsync(serviceName, userContext, cancellationToken);
            var response = await client.GetAsync(path, cancellationToken);

            await EnsureSuccessStatusCode(response, serviceName, path);

            var content = await response.Content.ReadAsStringAsync(cancellationToken);
            return JsonSerializer.Deserialize<TResponse>(content);
        }

        /// <summary>
        /// 执行POST请求
        /// </summary>
        public async Task<TResponse?> PostAsync<TRequest, TResponse>(
            string serviceName,
            string path,
            TRequest request,
            UserContext? userContext = null,
            CancellationToken cancellationToken = default)
        {
            using var client = await CreateClientAsync(serviceName, userContext, cancellationToken);

            var json = JsonSerializer.Serialize(request);
            var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

            var response = await client.PostAsync(path, content, cancellationToken);
            await EnsureSuccessStatusCode(response, serviceName, path);

            var responseContent = await response.Content.ReadAsStringAsync(cancellationToken);
            return JsonSerializer.Deserialize<TResponse>(responseContent);
        }

        /// <summary>
        /// 执行PUT请求
        /// </summary>
        public async Task<TResponse?> PutAsync<TRequest, TResponse>(
            string serviceName,
            string path,
            TRequest request,
            UserContext? userContext = null,
            CancellationToken cancellationToken = default)
        {
            using var client = await CreateClientAsync(serviceName, userContext, cancellationToken);

            var json = JsonSerializer.Serialize(request);
            var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

            var response = await client.PutAsync(path, content, cancellationToken);
            await EnsureSuccessStatusCode(response, serviceName, path);

            var responseContent = await response.Content.ReadAsStringAsync(cancellationToken);
            return JsonSerializer.Deserialize<TResponse>(responseContent);
        }

        /// <summary>
        /// 执行DELETE请求
        /// </summary>
        public async Task DeleteAsync(
            string serviceName,
            string path,
            UserContext? userContext = null,
            CancellationToken cancellationToken = default)
        {
            using var client = await CreateClientAsync(serviceName, userContext, cancellationToken);
            var response = await client.DeleteAsync(path, cancellationToken);
            await EnsureSuccessStatusCode(response, serviceName, path);
        }

        /// <summary>
        /// 执行自定义HTTP请求
        /// </summary>
        public async Task<HttpResponseMessage> SendAsync(
            string serviceName,
            HttpRequestMessage request,
            UserContext? userContext = null,
            CancellationToken cancellationToken = default)
        {
            using var client = await CreateClientAsync(serviceName, userContext, cancellationToken);
            var response = await client.SendAsync(request, cancellationToken);

            // 注意：这里不调用EnsureSuccessStatusCode，让调用者处理响应
            return response;
        }

        /// <summary>
        /// 批量获取服务实例地址
        /// </summary>
        public async Task<Dictionary<string, Uri>> GetBatchServiceAddressesAsync(
            IEnumerable<string> serviceNames,
            CancellationToken cancellationToken = default)
        {
            var result = new Dictionary<string, Uri>();
            var tasks = new List<Task>();

            foreach (var serviceName in serviceNames)
            {
                tasks.Add(Task.Run(async () =>
                {
                    try
                    {
                        var address = await GetServiceAddressAsync(serviceName, cancellationToken);
                        lock (result)
                        {
                            result[serviceName] = address;
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "批量获取服务地址失败: {ServiceName}", serviceName);
                    }
                }, cancellationToken));
            }

            await Task.WhenAll(tasks);
            return result;
        }

        /// <summary>
        /// 健康检查
        /// </summary>
        public async Task<bool> HealthCheckAsync(string serviceName, CancellationToken cancellationToken = default)
        {
            try
            {
                using var client = await CreateClientAsync(serviceName, cancellationToken: cancellationToken);
                var response = await client.GetAsync("/health", cancellationToken);

                var isHealthy = response.IsSuccessStatusCode;
                _metrics.RecordHealthCheck(serviceName, isHealthy);

                _logger.LogDebug("健康检查结果: {ServiceName} -> {IsHealthy}", serviceName, isHealthy);
                return isHealthy;
            }
            catch (Exception ex)
            {
                _metrics.RecordHealthCheck(serviceName, false);
                _logger.LogWarning(ex, "健康检查失败: {ServiceName}", serviceName);
                return false;
            }
        }

        #region Private Methods

        private static async Task EnsureSuccessStatusCode(HttpResponseMessage response, string serviceName, string path)
        {
            if (!response.IsSuccessStatusCode)
            {
                var content = await response.Content.ReadAsStringAsync();
                throw new ServiceException(
                    $"服务调用失败: {serviceName}{path} 返回状态码 {response.StatusCode}",
                    response.StatusCode,
                    content);
            }
        }

        private HttpClient AddMonitoringInterceptor(HttpClient client, string serviceName)
        {
            // 创建带监控的HttpClient包装器
            return new MonitoredHttpClient(client, serviceName, _metrics, _logger);
        }

        #endregion
    }

    /// <summary>
    /// 服务调用异常
    /// </summary>
    public class ServiceException : Exception
    {
        public System.Net.HttpStatusCode StatusCode { get; }
        public string? ResponseContent { get; }

        public ServiceException(string message, System.Net.HttpStatusCode statusCode, string? responseContent = null)
            : base(message)
        {
            StatusCode = statusCode;
            ResponseContent = responseContent;
        }

        public ServiceException(string message, System.Net.HttpStatusCode statusCode, Exception innerException)
            : base(message, innerException)
        {
            StatusCode = statusCode;
        }
    }

    /// <summary>
    /// 带监控的HttpClient包装器
    /// </summary>
    internal class MonitoredHttpClient : HttpClient
    {
        private readonly HttpClient _innerClient;
        private readonly string _serviceName;
        private readonly IServiceCommunicationMetrics _metrics;
        private readonly ILogger _logger;

        public MonitoredHttpClient(
            HttpClient innerClient,
            string serviceName,
            IServiceCommunicationMetrics metrics,
            ILogger logger)
        {
            _innerClient = innerClient;
            _serviceName = serviceName;
            _metrics = metrics;
            _logger = logger;
        }

        public override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var stopwatch = System.Diagnostics.Stopwatch.StartNew();

            try
            {
                var response = _innerClient.Send(request, cancellationToken);
                stopwatch.Stop();

                _metrics.RecordRequest(_serviceName, request.Method.Method, (int)response.StatusCode, stopwatch.ElapsedMilliseconds, true);

                return response;
            }
            catch (Exception ex)
            {
                stopwatch.Stop();
                _metrics.RecordRequest(_serviceName, request.Method.Method, 500, stopwatch.ElapsedMilliseconds, false);
                _logger.LogError(ex, "服务调用失败: {ServiceName} {Method} {Path}",
                    _serviceName, request.Method.Method, request.RequestUri?.PathAndQuery);
                throw;
            }
        }

        public override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var stopwatch = System.Diagnostics.Stopwatch.StartNew();

            try
            {
                var response = await _innerClient.SendAsync(request, cancellationToken);
                stopwatch.Stop();

                _metrics.RecordRequest(_serviceName, request.Method.Method, (int)response.StatusCode, stopwatch.ElapsedMilliseconds, true);

                _logger.LogDebug("服务调用成功: {ServiceName} {Method} {Path} -> {StatusCode} ({ElapsedMs}ms)",
                    _serviceName, request.Method.Method, request.RequestUri?.PathAndQuery, response.StatusCode, stopwatch.ElapsedMilliseconds);

                return response;
            }
            catch (Exception ex)
            {
                stopwatch.Stop();
                _metrics.RecordRequest(_serviceName, request.Method.Method, 500, stopwatch.ElapsedMilliseconds, false);
                _logger.LogError(ex, "服务调用失败: {ServiceName} {Method} {Path} ({ElapsedMs}ms)",
                    _serviceName, request.Method.Method, request.RequestUri?.PathAndQuery, stopwatch.ElapsedMilliseconds);
                throw;
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _innerClient?.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}